from typing import Optional, Union
from uuid import UUID
from datetime import timedelta

from django.utils import timezone as django_timezone
from django.utils.translation import gettext as _

from core import errors
from core.models import convert_to_uuid
from apps.app_auth_provider.models import AuthRecord, InternalUser, AuthCode


class AuthRecordManager:
    @staticmethod
    def create_auth_record(
            provider_type: str,
            redirect_uri: str,
            remote_ip: str,
            hostname: str,
            internal_user: Optional[InternalUser] = None,
            email: str = '',
            auth_status = AuthRecord.AuthStatus.INITIATED.value
    ) -> AuthRecord:
        obj = AuthRecord(
            provider_type=provider_type,
            redirect_uri=redirect_uri,
            remote_ip=remote_ip if remote_ip else '',
            hostname=hostname if hostname else '',
            internal_user=internal_user,
            email=email,
            auth_status=auth_status
        )
        obj.save(force_insert=True)
        return obj

    @staticmethod
    def get_auth_record(record_id: Union[str, UUID]) -> Optional[AuthRecord]:
        """
        raises: InvalidArgument
        """
        record_id = convert_to_uuid(record_id)
        if record_id is None:
            raise errors.InvalidArgument(message='id无效，不是一个有效的uuid。')

        return AuthRecord.objects.filter(id=record_id).first()


class AuthCodeManager:
    @staticmethod
    def create_auth_code(
            internal_user: InternalUser
    ) -> AuthCode:
        nt = django_timezone.now()
        obj = AuthCode(
            internal_user=internal_user,
            used=False,
            expired_at=nt + timedelta(minutes=3)
        )
        obj.save(force_insert=True)
        return obj

    @staticmethod
    def get_auth_code(code_id: str) -> Optional[AuthCode]:
        """
        查询授权码

        :return:
            AuthCode    # 授权码
            None        # 授权码不存在
        """
        code_id = convert_to_uuid(code_id)
        if code_id is None:
            return None

        return AuthCode.objects.select_related('internal_user').filter(id=code_id).first()

    @staticmethod
    def get_valid_auth_code(code_id: str) -> Optional[AuthCode]:
        """
        查询授权码，并验证授权码是否有效

        :return:
            AuthCode    # 有效的授权码
            None        # 授权码不存在

        :raises: ConflictError
        """
        auth_code = AuthCodeManager.get_auth_code(code_id=code_id)
        if auth_code is None:
            return None

        if auth_code.used:
            raise errors.ConflictError(message=_('授权码无效，已使用。'))

        if auth_code.expired_at < django_timezone.now():
            raise errors.ConflictError(message=_('授权码无效，已过期。'))

        if not auth_code.internal_user:
            raise errors.ConflictError(message=_('授权码不可用，未关联用户。'))

        return auth_code
